package com.ubxtech.gateway.handler;

import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.ubxtech.core.exception.ErrorCodeCore;
import com.ubxtech.core.exception.RRException;
import com.ubxtech.gateway.util.ResponseUtil;
import io.netty.channel.ConnectTimeoutException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.core.annotation.Order;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebExceptionHandler;
import reactor.core.publisher.Mono;

/**
 * @author Victor.Xiao
 * @since 2023-08-18 18:12
 **/
@Order(-10)
@Slf4j
public class GlobalExceptionHandler implements WebExceptionHandler {

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        log.error("[网关异常处理],异常", ex);
        if (exchange.getResponse().isCommitted()) {
            return Mono.error(ex);
        }
        //springboot3 会报错 先注释 具体逻辑参考SentinelGatewayBlockExceptionHandler
//        return handleBlockedRequest(exchange, ex).flatMap(response -> writeResponse(exchange,ex));
        return writeResponse(exchange,ex);
    }

    private Mono<Void> writeResponse( ServerWebExchange exchange,Throwable ex) {
        //限流
        if (ex instanceof ParamFlowException) {
            return ResponseUtil.write(exchange.getResponse(), ErrorCodeCore.SENTINEL_EXCEPTION);
        }
        else if (ex instanceof NotFoundException) {
            return ResponseUtil.write(exchange.getResponse(), ErrorCodeCore.NOT_FOUND);
        }
        else if (ex instanceof ConnectTimeoutException) {
            return ResponseUtil.write(exchange.getResponse(), ErrorCodeCore.CONNECT_TIME_OUT);
        }
        else if (ex instanceof ResponseStatusException) {
            ResponseStatusException responseStatusException = (ResponseStatusException) ex;

            return ResponseUtil.write(exchange.getResponse(), responseStatusException.getStatusCode().value(), ex.getMessage());
        }
        else if (ex instanceof RRException) {
            RRException rrException = (RRException) ex;
            return ResponseUtil.write(exchange.getResponse(), rrException.getCode(), rrException.getMsg());
        }
        return ResponseUtil.write(exchange.getResponse(), ErrorCodeCore.INTERNAL_SERVER_ERR);
    }

    private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
        return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
    }
}
